from django.shortcuts import render, redirect
# 导包
from django.http import HttpResponse, HttpResponseRedirect, JsonResponse
# 导入类视图
from django.views import View
import jwt
from myapp.models import User, Pics, Goods, Cate, Comment, UserFlow
import json

from rest_framework.response import Response
from rest_framework.views import APIView
# 导入加密库
import hashlib
# 导入图片库
# 绘画库
from PIL import ImageDraw
# 字体库
from PIL import ImageFont
# 图片库
from PIL import Image
# 随机库
import random
# 文件流
import io

import requests

# 导入上传文件夹配置
from mydjango.settings import UPLOAD_ROOT
import os

# 导入原生sql模块
from django.db import connection

import jwt

# 导入redis数据库
import redis

# 导入时间模块
import time

# 导入公共目录变量
from mydjango.settings import BASE_DIR

# 导包
from django.db.models import Q, F
from django.core.paginator import Paginator

# 导入dwebsocket的库
from dwebsocket.decorators import accept_websocket
import uuid
from myapp.myser import UserSer, PicsSer, GoodsSer, CateSer, CommentSer, UserFlowSer
import redis
from django.utils.deprecation import MiddlewareMixin

# 定义地址和端口
host = '127.0.0.1'
port = 6379
# 建立redis连接
r = redis.Redis(host=host, port=port)

import pymongo

# 建立mongo连接对象
mongo_client = pymongo.MongoClient(host='localhost', port=27017)
# 导入bson
from bson import json_util as jsonb


# 商品检索接口
class GoodsSerach(APIView):
    def get(self, request):
        # 接收参数
        word = request.GET.get("word", None)
        # 检索  模糊匹配 | 代表或者  （， &）代表并且
        goodslist = Goods.objects.filter(Q(name__icontains=word) | Q(desc__icontains=word))
        # goodslist= Goods.objects.filter(name__icontains=word)
        # 序列化
        goods_ser = GoodsSer(goodslist, many=True)
        return Response(goods_ser.data)


# 工具方法，获取前n名的数据
def get_top_n(num):
    # 获取redis数据
    goods_click = r.zrange('good_rank', 0, -1, desc=True, withscores=True)[:num]
    # 获取mysql中数据
    goods = Goods.objects.in_bulk([int(item[0]) for item in goods_click])
    # 合并操作
    res = []
    for item in goods_click:
        # 遍历列表
        # 捕获异常，防止redis和mysql数据不同步问题
        try:
            res.append({item[1]: goods[int(item[0])]})
        except Exception as e:
            pass
    return res


# 商品排行榜数据视图
class GoodRank(APIView):
    def get(self, request):
        # 获取排名前n的数据
        get_res = get_top_n(10)
        res = []
        # 遍历进行序列化
        for dic in get_res:
            for k, v in dic.items():
                # 序列化
                data = GoodsSer(v).data
                # 将商品点击数附加到商品序列化数据中
                data['clicks'] = k
                res.append(data)
        return Response(res)


# 新的商品参与排名
class GoodsClick(APIView):
    def get(self, request):
        # 接收参数
        id = request.GET.get("id", None)
        # 修改商品的点击数
        r.zincrby("good_rank", 1, int(id))
        get_top_n(10)
        return Response({"message": "访问加1"})


# 对结果集美化方法
def dictfetchall(cursor):
    # 获取游标描述
    desc = cursor.description

    return [

        dict(zip([col[0] for col in desc], row))

        for row in cursor.fetchall()

    ]


# 商品被多少人关注
class GoodFlow(View):
    def get(self, request):
        gid = request.GET.get("gid")
        # 建立游标对象
        cursor = connection.cursor()
        # 执行sql语句
        cursor.execute('select a.username from user a left join userflow b on b.uid = a.id where gid = %s' % str(gid))
        result_user = dictfetchall(cursor)
        # 返回结果
        return HttpResponse(json.dumps(result_user, ensure_ascii=False), content_type='application/json')


# 商品关注接口(查询用户关注过的商品列表)
class UidFlow(View):
    def get(self, request):
        uid = request.GET.get("uid", None)

        # 建立游标对象
        cursor = connection.cursor()

        # 执行sql语句
        cursor.execute(
            'select a.id,a.name,a.create_time from goods a left join userflow b on a.id = b.gid where b.uid = %s ' % str(
                uid))

        # 获取结果
        # result = cursor.fetchall()
        result = dictfetchall(cursor)

        # 返回结果 手动序列化
        return HttpResponse(json.dumps(result, ensure_ascii=False, indent=4, default=str),
                            content_type='application/json')


# 关注商品接口(取关)
class GetFlow(APIView):
    def get(self, request):

        id = request.GET.get("gid", None)
        uid = request.GET.get("uid", None)
        type = request.GET.get("type", 1)

        if int(type) == 1:

            # 关注
            userflow = UserFlow(gid=int(id), uid=int(uid))
            try:
                userflow.save()
                message = "关注成功"
                goods = Goods.objects.filter(id=int(id)).first()
                goods.flow = goods.flow + 1
                goods.save()
            except Exception as e:
                print(str(e))
                message = "不能重复关注"
                pass

        elif int(type) == 2:
            # 取关
            UserFlow.objects.filter(gid=int(id), uid=int(uid)).delete()
            message = "取关成功"
            goods = Goods.objects.filter(id=int(id)).first()
            goods.flow = goods.flow - 1
            goods.save()

        else:
            # 批量取关
            ids = request.GET.get("ids", None)
            # 批量操作
            UserFlow.objects.filter(uid=int(uid)).delete()
            # 强转
            id_list = eval(ids)

            for id in id_list:
                userflow = UserFlow(gid=int(id), uid=int(uid))
                userflow.save()

            message = "批量关注成功"

        return Response({'message': message})


# 用户列表
class UserList(APIView):
    def get(self, request):
        # 查询
        user = User.objects.filter()
        # 序列化
        user_ser = UserSer(user, many=True)
        return Response(user_ser.data)


# 将评论存储到mongo
class InsertCommentMongo(APIView):

    def get(self, request):
        # 接收参数
        gid = request.GET.get('gid')
        uid = request.GET.get('uid')
        content = request.GET.get('content')

        # 建立数据库
        db = mongo_client.md
        # 建立表
        table = db.comment
        # 存储数据
        table.insert({'gid': str(gid), 'uid': str(uid), 'content': content})
        return Response({'code': 200, 'message': '存储mongo成功'})


# 评论列表
class CommentList(APIView):

    def get(self, request):
        # 商品id
        id = request.GET.get("id", None)

        # 查询评论
        comment = Comment.objects.filter(gid=int(id)).order_by("-id")

        # 自制分页器

        page_num = request.GET.get("page", 1)
        page_num = int(page_num)
        paginator = Paginator(comment, 2)
        per_page = paginator.get_page(page_num)
        resp = {}
        resp['code'] = 200
        resp['data'] = CommentSer(per_page, many=True).data
        resp['next'] = page_num + 1
        resp['prev'] = page_num - 1
        resp['nums'] = list(range(1, paginator.num_pages + 1))

        return Response(resp)


# 反序列化入库
class InsertComment(APIView):
    def post(self, request):
        # 初始化参数
        uid = request.POST.get("uid", None)
        if r.get(str(uid)):
            return Response({'code': 403, 'message': '您评论的太快了，歇一会儿'})
        comment = CommentSer(data=request.data)

        # 数据校验
        if comment.is_valid():
            comment.save()
            # 插入评论标记
            r.set(str(uid), 123)
            r.expire(str(uid), 30)
        return Response({'code': 200, 'message': '恭喜，评论成功'})


# 统计在线人数
class GetOnline(APIView):
    def get(self, request):
        # 获取客户
        if 'HTTP_X_FORWARDED_FOR' in request.META:
            ip = request.META.get('HTTP_X_FORWARDED_FOR')
        else:
            ip = request.META.get('REMOTE_ADDR')
        # 对IP进行存储
        r.sadd("online", ip)
        # 设置超时时间  单位为秒
        r.expire("online", 20)
        # 获取在线人数的数量
        myset = r.smembers("online")
        return Response({"online": len(myset)})


# 更新商品标签
class UpdateTags(APIView):
    def get(self, request):
        id = request.GET.get('id', None)
        tags = request.GET.get('tags', None)
        tags = tags.split(",")
        # 建立数据库对象
        db = mongo_client.md
        # 建立表对象
        table = db.mytag

        # 排重,商品id不能重复
        res = table.find({'gid': str(id)}).count()
        if res > 0:
            table.update({'gid': str(id)}, {"$set": {'tags': tags}})
            return Response({'message': '入库成功'})


# 商品更新接口
class UpdateGoods(APIView):
    def post(self, request):
        id = request.POST.get('id', 'null')
        print(id)
        pass
        name = request.POST.get('name', 'null')
        desc = request.POST.get('desc', 'null')
        print(desc)
        parms = request.POST.get('parms', 'null')
        price = request.POST.get('price', 'null')
        cate_id = request.POST.get('cate_id')

        # 排重
        good = Goods.objects.filter(id=id).first()
        # 进行入库
        good.name = name
        good.desc = desc
        good.parms = parms
        good.price = price
        good.cate_id = cate_id

        good.save()

        res = {}
        res['code'] = 200
        res['id'] = good.id
        res['message'] = '商品更新成功'

        return Response(res)


# 获取商品标签
class GetTags(View):
    def get(self, request):
        id = request.GET.get('id', None)
        # 建立数据库对象
        db = mongo_client.md
        # 建立表对象
        table = db.mytag
        # 查询数据
        res = table.find_one({"gid": str(id)})
        return HttpResponse(jsonb.dumps(res, ensure_ascii=False))


# 商品标签添加接口
class InsertTags(APIView):
    def get(self, request):
        id = request.GET.get('id', None)
        tags = request.GET.get('tags', None)
        tags = tags.split(",")

        # 建立数据库对象
        db = mongo_client.md
        # 建立表对象
        table = db.mytag
        # 再存入redis一份
        # for i in range(len(tags)):
        #     # print(tags[i])
        #     r.sadd('testset', str(tags[i]))
        # redis_set = r.smembers('testset')

        # 排重操作
        # 查询
        res = table.find({"gid": str(id)}).count()
        if res > 0:
            return Response({'message': '重复数据'})
        else:
            # 入库操作
            table.insert({"gid": str(id), "tags": tags})
            return Response({'message': '入库成功'})


# 商品入库接口
class AddGoods(APIView):
    def get(self, request):
        # 查询所有分类
        cate_list = Cate.objects.all()
        cates = CateSer(cate_list, many=True)
        return Response({'code': 200, 'cate_list': cates.data})

    def post(self, request):
        # 接收参数
        name = request.POST.get('name')
        desc = request.POST.get('desc')
        # 将商品规格存储到redis中
        r.set('desc', desc)
        parms = request.POST.get('parms')
        cate_id = request.POST.get('cate_id')
        price = request.POST.get('price')

        # 商品排重
        goods = Goods.objects.filter(name=name).first()

        if goods:
            res = {}
            res['code'] = 405
            res['msg'] = '该商品已经存在'
            return Response(res)

        # 进行入库
        goods = Goods(name=name, desc=desc,
                      parms=parms, cate_id=cate_id, price=price)
        goods.save()

        res = {}
        res['code'] = 200
        res['id'] = goods.id
        res['msg'] = '商品添加成功'

        return Response(res)


# 商品列表页
class GoodsList(APIView):
    def get(self, request):
        # # 当前页
        # page = int(request.GET.get("page", 1))
        # # 一页有多少条商品
        # size = int(request.GET.get("size", 1))
        # # 定义从哪开始切
        # data_start = (page - 1) * size
        # # 定义切到哪
        # data_end = page * size
        # # 查询数据
        # goodslist = Goods.objects.all()[data_start:data_end]
        # # 查询总数
        # count = Goods.objects.count()
        # # 序列化操作
        # goods_ser = GoodsSer(goodslist,many=True).data
        # # 上一页
        # prev = page - 1
        # # 下一页
        # next = page + 1
        # res = {}
        # res['total'] = count
        # res['data'] = goods_ser
        # res['prev'] = prev
        # res['next'] = next
        # return Response(res)

        # 自制分页器
        goods = Goods.objects.all()
        page_num = request.GET.get("page", 1)
        page_num = int(page_num)
        paginator = Paginator(goods, 2)
        per_page = paginator.get_page(page_num)
        resp = {}
        resp['code'] = 200
        resp['data'] = GoodsSer(per_page, many=True).data
        resp['next'] = page_num + 1
        resp['prev'] = page_num - 1
        resp['nums'] = list(range(1, paginator.num_pages + 1))

        return Response(resp)


class GoodItem(APIView):
    def get(self, request):
        gid = request.GET.get("gid")

        good = Goods.objects.filter(id=gid).first()
        resp = {}
        resp['code'] = 200
        resp['message'] = '商品获取成功'
        resp['data'] = GoodsSer(good).data

        return Response(resp)
